package com.shinbada.modules.sys.utils;

import com.google.common.collect.Lists;
import com.shinbada.common.Common;
import com.shinbada.common.utils.CacheUtils;
import com.shinbada.common.utils.SpringContextHolder;
import com.shinbada.config.properties.ShinProperites;
import com.shinbada.core.security.shiro.JWTToken;
import com.shinbada.core.security.shiro.JWTUtil;
import com.shinbada.core.service.BaseService;
import com.shinbada.modules.sys.entity.*;
import com.shinbada.modules.sys.mapper.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.InvalidSessionException;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 用户工具类
 *
 * @author initcap
 * @version 2016-12-05
 */
@Slf4j
public class UserUtils {

    public static final String USER_CACHE = "userCache";
    public static final String USER_CACHE_ID_ = "id_";
    public static final String USER_CACHE_LOGIN_NAME_ = "ln";
    public static final String USER_CACHE_LIST_BY_OFFICE_ID_ = "oid_";
    public static final String CACHE_ROLE_LIST = "roleList";
    public static final String CACHE_TOP_MENU = "topMenu";
    public static final String CACHE_MENU_LIST = "menuList";
    public static final String CACHE_DATA_RULE_LIST = "dataRuleList";
    public static final String CACHE_SPLIT = "_user_id_";
    public static final String SYSTEM_USER_LOGIN_NAME = "system";
    public static final String ADMINISTRATOR_USER_LOGIN_NAME = "administrator";
    public static final String DEFAULT_COMPANY_ID = "d84311d5280c466f8c7bc58caa02b288";
    private static final String SYSTEM_USER_LOGIN_PASSWORD = "4655200cc74876831d5a56b85e345008ecfb793d43d66025a3007187";
    private static UserMapper userMapper = SpringContextHolder.getBean(UserMapper.class);
    private static RoleMapper roleMapper = SpringContextHolder.getBean(RoleMapper.class);
    private static MenuMapper menuMapper = SpringContextHolder.getBean(MenuMapper.class);
    private static OfficeMapper officeMapper = SpringContextHolder.getBean(OfficeMapper.class);
    private static DataRuleMapper dataRuleMapper = SpringContextHolder.getBean(DataRuleMapper.class);
    private static SysSettingMapper settingMapper = SpringContextHolder.getBean(SysSettingMapper.class);
    private static SysConfigMapper configMapper = SpringContextHolder.getBean(SysConfigMapper.class);

    public static HttpServletRequest getRequest() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) {
            return null;
        }
        return servletRequestAttributes.getRequest();
    }

    public static HttpServletResponse getResponse() {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (servletRequestAttributes == null) {
            return null;
        }
        return servletRequestAttributes.getResponse();
    }

    /**
     * 根据ID获取用户
     *
     * @param id 用户主键
     * @return 取不到返回null
     */
    public static User get(String id) {
        User user = (User) CacheUtils.get(USER_CACHE, USER_CACHE_ID_ + id);
        if (user == null) {
            user = userMapper.get(id);
            if (user == null) {
                return null;
            }
            CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
            CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
        }
        return user;
    }

    public static SysSetting getSetting() {
        return getSetting(getUser().getCompany().getId());
    }

    public static SysSetting getSetting(String companyId) {
        return settingMapper.getByCompanyId(companyId);
    }

    public static SysConfig getConfig() {
        if (CacheUtils.get("sys.config", "1") == null) {
            CacheUtils.put("sys.config", "1", configMapper.get("1"));
        }
        return (SysConfig) CacheUtils.get("sys.config", "1");
    }

    public static String getUserNameById(String id) {
        User user = get(id);
        if (user == null) {
            return "";
        } else {
            return user.getName();
        }
    }


    /**
     * 根据登录名获取用户
     *
     * @param loginName
     * @return 取不到返回null
     */
    public static User getByLoginName(String loginName) {
        User user = (User) CacheUtils.get(USER_CACHE, USER_CACHE_LOGIN_NAME_ + loginName);
        if (user == null) {
            if (SYSTEM_USER_LOGIN_NAME.equals(loginName)) {
                User system = new User(Common.IS_SYSTEM_USER_ID);
                system.setName("系统");
                system.setLoginFlag(ShinProperites.YES);
                system.setPassword(SYSTEM_USER_LOGIN_PASSWORD);
                user = system;
            } else if (ADMINISTRATOR_USER_LOGIN_NAME.equals(loginName)) {
                User administrator = new User(Common.IS_ADMIN_USER_ID);
                administrator.setName("辛巴达超管");
                administrator.setLoginFlag(ShinProperites.YES);
                administrator.setPassword(getConfig().getAdministratorPassword());
                administrator.setCompanyId(getConfig().getAdministratorCompanyId());
                administrator.setCompany(new Office(getConfig().getAdministratorCompanyId()));
                user = administrator;
            } else {
                user = userMapper.getByLoginName(new User(null, loginName));
                if (user == null) {
                    return null;
                }
            }
            CacheUtils.put(USER_CACHE, USER_CACHE_ID_ + user.getId(), user);
            CacheUtils.put(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName(), user);
        }
        return user;
    }

    /**
     * 清除当前用户缓存
     */
    public static void clearCache() {
        removeCache(CACHE_ROLE_LIST);
        removeCache(CACHE_DATA_RULE_LIST);
        removeCache(CACHE_TOP_MENU);
        removeCache(CACHE_MENU_LIST);
        UserUtils.clearCache(getUser());
    }

    /**
     * 清除指定用户缓存
     *
     * @param user
     */
    public static void clearCache(User user) {
        log.info("清理指定用户缓存:  用户id : {}, 用户新登录名 : {}, 用户旧登录名 : {}", user.getId(), user.getLoginName(), user.getOldLoginName());
        CacheUtils.remove(USER_CACHE, USER_CACHE_ID_ + user.getId());
        CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getLoginName());
        CacheUtils.remove(USER_CACHE, USER_CACHE_LOGIN_NAME_ + user.getOldLoginName());
        if (user.getOffice() != null && user.getOffice().getId() != null) {
            CacheUtils.remove(USER_CACHE, USER_CACHE_LIST_BY_OFFICE_ID_ + user.getOffice().getId());
        }
    }

    /**
     * 获取当前用户
     *
     * @return 取不到返回 new User()
     */
    public static User getUser() {
        String token = getToken();
        if (token != null) {
            User user = getByLoginName(JWTUtil.getLoginName(token));
            if (user != null) {
                return user;
            }
            return new User();
        }
        // 如果没有登录，则返回实例化空的User对象。
        return new User();
    }

    /**
     * 获取用户的主管理域
     *
     * @return 管理域信息 部门的parentids + parentid + ,
     */
    public static String getDomainPath() {
        return getUser().getOffice().getDomainPath();
    }

    /**
     * 获取用户所有的管理域，包括额外授权的
     *
     * @return 管理域信息集合
     */
    public static List<String> listDomains() {
        User currentUser = getUser();
        List<String> domains = new ArrayList<>();
        String userdomains = currentUser.getDomains();
        String[] domainArr = userdomains.split("｜");
        domains.addAll(Arrays.asList(domainArr));
        domains.add(getDomainPath());
        return domains;
    }

    /**
     * 获取当前用户角色列表
     *
     * @return
     */
    public static List<Role> getRoleList() {
        @SuppressWarnings("unchecked")
        List<Role> roleList = (List<Role>) getCache(CACHE_ROLE_LIST);
        if (roleList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                roleList = roleMapper.findAllList(new Role());
            } else {
                roleList = user.getRoleList();
            }
            putCache(CACHE_ROLE_LIST, roleList);
        }
        return roleList;
    }

    /**
     * 获取当前用户授权菜单
     *
     * @return
     */
    public static List<Menu> getMenuList() {
        @SuppressWarnings("unchecked")
        List<Menu> menuList = (List<Menu>) getCache(CACHE_MENU_LIST);
        if (menuList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                menuList = menuMapper.findAllList(new Menu());
            } else {
                Menu m = new Menu();
                m.setUserId(user.getId());
                menuList = menuMapper.findByUserId(m);
            }
            putCache(CACHE_MENU_LIST, menuList);
        }
        return menuList;
    }

    /**
     * 获取当前用户授权数据权限
     *
     * @return
     */
    public static List<DataRule> getDataRuleList() {
        @SuppressWarnings("unchecked")
        List<DataRule> dataRuleList = (List<DataRule>) getCache(CACHE_DATA_RULE_LIST);
        if (dataRuleList == null) {
            User user = getUser();
            if (user.isAdmin()) {
                dataRuleList = Lists.newArrayList();
            } else {
                dataRuleList = dataRuleMapper.findByUserId(user);
            }
            putCache(CACHE_DATA_RULE_LIST, dataRuleList);
        }
        return dataRuleList;
    }

    /**
     * 获取当前用户授权菜单
     *
     * @return
     */
    public static Menu getTopMenu() {
        Menu topMenu = (Menu) getCache(CACHE_TOP_MENU);
        if (topMenu == null) {
            topMenu = menuMapper.get("1");
            putCache(CACHE_TOP_MENU, topMenu);
        }
        return topMenu;
    }

    /**
     * 获取当前用户有权限访问的部门
     *
     * @return
     */
    public static List<Office> getOfficeList() {
        User user = getUser();
        if (user.isAdmin()) {
            Office office = new Office();
            office.setSupper(true);
            return officeMapper.findAllList(office);
        } else {
            Office office = new Office();
            office.setCompanyId(user.getCompany().getId());
            BaseService.dataRuleFilter(office);
            return officeMapper.findList(office);
        }
    }

    /**
     * 获取当前用户有权限访问的部门
     *
     * @return
     */
    public static List<Office> getOfficeAllList() {
        User user = getUser();
        Office office = new Office();
        if (user.isAdmin()) {
            office.setSupper(true);
        }
        return officeMapper.findAllList(office);
    }

    /**
     * 获取授权主要对象
     */
    public static Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    /**
     * 获取当前登录者对象
     */
    public static String getToken() {
        try {
            Subject subject = SecurityUtils.getSubject();
            Object token = subject.getPrincipal();
            if (token != null) {
                return token.toString();
            }
        } catch (UnavailableSecurityManagerException e) {

        } catch (InvalidSessionException e) {

        }
        return null;
    }

    public static Session getSession() {
        try {
            Subject subject = SecurityUtils.getSubject();
            Session session = subject.getSession(false);
            if (session == null) {
                session = subject.getSession();
            }
            if (session != null) {
                return session;
            }
        } catch (InvalidSessionException e) {

        }
        return null;
    }

    /**
     * 根据key，获取和当前用户的缓存
     *
     * @param key
     * @return
     */
    public static Object getCache(String key) {
        return CacheUtils.get(USER_CACHE, key + CACHE_SPLIT + getUser().getId());
    }

    public static void putCache(String key, Object value) {
        CacheUtils.put(USER_CACHE, key + CACHE_SPLIT + getUser().getId(), value);
    }

    public static void removeCache(String key) {
        CacheUtils.remove(USER_CACHE, key + CACHE_SPLIT + getUser().getId());
    }

    /**
     * 导出Excel调用,根据姓名转换为ID
     */
    public static User getByUserName(String name) {
        User u = new User();
        u.setName(name);
        List<User> list = userMapper.findList(u);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        } else {
            return new User();
        }
    }

    public static boolean keepReference() {
        return true;
    }

    public static User getByNo(String no, String companyId) {
        User u = new User();
        u.setNo(no);
        u.setCompanyId(companyId);
        User user = userMapper.getByNo(u);
        if (user == null) {
            user = new User();
        }
        return user;
    }

    public static User getByNo(String no) {
        return getByNo(no, UserUtils.getUser().getCompany().getId());
    }

    /**
     * 导出Excel使用，根据名字转换为id
     */
    public static Office getByOfficeName(String name) {
        Office o = new Office();
        o.setName(name);
        List<Office> list = officeMapper.findList(o);
        if (CollectionUtils.isNotEmpty(list)) {
            return list.get(0);
        } else {
            return new Office();
        }
    }

    public static List<User> listByOfficeAndPostAndUser(Office office, Post post, User user) {
        return userMapper.listByOfficeAndPostAndUser(office, post, user);
    }

    public static boolean hasPermission(String permission) {
        return SecurityUtils.getSubject().isPermitted(permission);
    }

    public static void authSystem() {
        SecurityUtils.setSecurityManager(SpringContextHolder.getBean(SecurityManager.class));
        SecurityUtils.getSubject().login(new JWTToken(JWTUtil.createAccessToken(SYSTEM_USER_LOGIN_NAME, SYSTEM_USER_LOGIN_PASSWORD)));
    }

    public static void authSystemCompanyId(String companyId) {
        User sys = getByLoginName(SYSTEM_USER_LOGIN_NAME);
        sys.setCompany(new Office(companyId));
        sys.setCompanyId(companyId);
        authSystem();
    }

    public static void logout() {
        String token = UserUtils.getToken();
        if (StringUtils.isNotBlank(token)) {
            UserUtils.clearCache();
            UserUtils.getSubject().logout();
        }
    }

    public static void authTestJunit(String username) {
        SecurityUtils.setSecurityManager(SpringContextHolder.getBean(SecurityManager.class));
        SecurityUtils.getSubject().login(new JWTToken(JWTUtil.createAccessToken(username, getByLoginName(username).getPassword())));
    }

}
